#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include<time.h>
#include<mpi.h>
#define MAX 100

char arruma(char letra);
int palindromo(char string[]);
void primo(char palindromo[]);
void crivo();

int intervalo[10000];
int nprimos = 0;

int main(int argc, char *argv[]) {
  FILE *pFile;
  long lSize, auxlSize;
  
  pFile = fopen ( "wikipedia.txt" , "rb" );
  if (pFile==NULL) {fputs ("File error",stderr); exit (1);}

  // obtain file size:
  fseek (pFile , 0 , SEEK_END);
  lSize = ftell (pFile);
  rewind (pFile); //volta para o inÃ­cio do arquivo

  /* the whole file is now loaded in the memory buffer. */
  int i = 0, j = 0, k = 0, npalindromosIN = 0, npalindromosOUT = 0, npalindromos = 0;
  char palavra[100000];//, bufferOUT[auxlSize+1], bufferIN[auxlSize+1];
  int ret, numTasks, myRank;
  MPI_Status stat;
	
  crivo();
  ret = MPI_Init(&argc, &argv);
  if(ret != MPI_SUCCESS)
		exit(1);
		
  MPI_Comm_size(MPI_COMM_WORLD, &numTasks);
  MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
  
  auxlSize = ceil(lSize / numTasks);
  
  char bufferOUT[auxlSize+1], bufferIN[auxlSize+1];
  
  if(myRank == 0) {
	for(i=1; i<numTasks; i++) {
		if (lSize < auxlSize) {
  			fread (bufferOUT,sizeof(char),lSize,pFile);
  			bufferOUT[lSize] = '\0';
  		} else {
		 	fread (bufferOUT,sizeof(char),auxlSize,pFile);
		 	bufferOUT[auxlSize] = '\0';
		 	lSize = lSize - auxlSize;
		}

		MPI_Send(&bufferOUT, strlen(bufferOUT), MPI_CHAR, i, 1, MPI_COMM_WORLD);
	}

	for(i=1; i<numTasks; i++) {
		MPI_Recv(&npalindromosIN, 1, MPI_INT, i, 1, MPI_COMM_WORLD, &stat);
		npalindromos += npalindromosIN;
	}
	
	printf("O arquivo tem %d palindromos\ne %d palindromos primos\n", npalindromos, nprimos);
	
  } else { //processos escravos
	
		MPI_Recv(&bufferIN, auxlSize, MPI_CHAR, 0, 1, MPI_COMM_WORLD, &stat);
		
	    i = 0;
	    j = 0;
	    while(i < strlen(bufferIN)) {
		    while(isalpha(bufferIN[i])) {
			  palavra[j] = bufferIN[i]; 
			  j++; 
			  i++;
		    }
		    palavra[j] = '\0';
		    j = 0;
		    
		    if(palindromo(palavra) == 0 && strlen(palavra) > 1) {
			  primo(palavra);
			  npalindromosOUT++;
		    }

		    i++;
	    }
	    MPI_Send(&npalindromosOUT, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
  }

  // terminate
  MPI_Finalize();
  fclose (pFile);

  return 0;
}

int palindromo(char string[]) {

  char strcomespaco[MAX],str1[MAX], str2[MAX];
  int tamcomespaco,tam, i, j;

  strcpy(strcomespaco,string);

  tamcomespaco = strlen(strcomespaco);

  for(i=0,j=0;i<tamcomespaco;i++) {
     strcomespaco[i] = arruma(strcomespaco[i]);
    if(isalpha(strcomespaco[i])) {
        str1[j] = strcomespaco[i];
        j++;
    }
  }

    str1[j]='\0';

    tam = strlen(str1);

    for (i=tam-1,j=0;i>=0;i--,j++){
    str2[j] = str1[i];
    if(str2[j] != str1[j])//Verifica se a primeira letra Ã© diferente da ultima, se for nÃ£o Ã© palindromo, se nÃ£o for continua comparando atÃ© o fim da palavra.
        return 1;
    }

    str2[tam] = '\0';


        return 0;
}

char arruma(char letra) {
    if(letra >= 65 && letra <= 90)
        letra = letra + 32;

    return letra;
}

void primo(char palindromo[]) {
	 int i, l;
     int tam = strlen(palindromo), soma = 0;
     
     for(i = 0; i < tam; i++) {
        soma += palindromo[i];       
     }
     
     for(l = 0; l < 10000; l++) {
        if(intervalo[l] != -1) {
            if(intervalo[l] == soma)
                nprimos++;
        }
     }
     
}

void crivo() {
    int i, j, k;
    int limite, div = 0;
    
     for(i = 0; i < 10000; i++) {
        intervalo[i] = i + 1;    
     }

     limite = sqrt(10000);

     for(i = 0; i < 10000; i++) {
            if(intervalo[i] > 1) {

		      for (j = 1; j <= intervalo[i]; j++) {
                    if (intervalo[i] % j == 0) {
                        div++;
                    }
              }
	    
            if(div == 2) { //se e primo
                for(k = i+1; k < 10000; k++) {
                     if(intervalo[k] % intervalo[i] == 0) {
                          //remover da lista
                         intervalo[k] = -1;
                     }
                }
            }
            else {
               intervalo[i] = -1;
            }
            div = 0;

            if(intervalo[i] == limite) {
              break;
           }
        }
        else {
            intervalo[i] = -1;    
        }
     }
}
